package ru.magicreader.client.view;

import ru.magicreader.client.I18nConstants;
import ru.magicreader.client.controller.MainState;
import ru.magicreader.client.model.Feed;
import ru.magicreader.client.model.Settings;
import ru.magicreader.client.model.User;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;

public class MainPage implements MainState.MainStateHandler {
	private static final String TAGCLOUD_SUBPANEL_HEIGHT = "190px";
	private static final String LOGOUT_URL = GWT.getModuleBaseURL() + "feedServlet?action=logout";
	private I18nConstants i18nc = (I18nConstants)GWT.create(I18nConstants.class);
	private final MainState controllerState;
	private User user;
	private TextBox newFeedTextbox;
	private CheckBox importantCheckbox;
	private Label userLoginLabel;
	private Anchor logoutAnchor;
	private Button newFeedButton;
	private SettingsPanel settingsPanel;
	private FeedsPanel feedsPanel;

	public MainPage(MainState controllerState) {
		this.controllerState = controllerState;
	}
	
	private Anchor newLocaleAnchor(String localeName, String currentLocale) {
		Anchor ret = new Anchor();
		ret.setText(localeName);
		if(!localeName.equals(currentLocale))
			ret.setHref(getLocalizedUrl(localeName));
		
		return ret;
	}

	public void load() {
		HorizontalPanel topPanel = new HorizontalPanel();
		topPanel.setStyleName("topPanel");
		{
			//left side
			topPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
			HorizontalPanel leftSide = new HorizontalPanel();
			leftSide.setStyleName("topPanelLeftSide");
			leftSide.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
			topPanel.add(leftSide);
			{
				userLoginLabel = new Label();
				leftSide.add(userLoginLabel);
				logoutAnchor = new Anchor();
				logoutAnchor.setText(i18nc.logout());
				logoutAnchor.setHref(LOGOUT_URL);
				logoutAnchor.setStyleName("logoutAnchor");
				leftSide.add(logoutAnchor);
			}
			
			//right side
			topPanel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
			HorizontalPanel rightSide = new HorizontalPanel();
			rightSide.setStyleName("topPanelRightSide");
			rightSide.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
			topPanel.add(rightSide);
			{
				//feedback anchor
				Anchor feedbackAnchor = new Anchor();
				feedbackAnchor.setText(i18nc.feedback());
				feedbackAnchor.setHref("mailto:weekens@gmail.com?subject=MagicReader%20feedback");
				feedbackAnchor.setTarget("_blank"); //to open in new window
				feedbackAnchor.setTitle(i18nc.feedbackTooltip());
				rightSide.add(feedbackAnchor);
				
				//help anchor
				Anchor helpAnchor = new Anchor();
				helpAnchor.setText(i18nc.help());
				String currentLocale = LocaleInfo.getCurrentLocale().getLocaleName();
				if(currentLocale.equals("default")) currentLocale = "en";
				helpAnchor.setHref("help/" + currentLocale + "/help.html");
				helpAnchor.setTarget("_blank"); //to open in new window
				helpAnchor.setTitle(i18nc.helpTooltip());
				rightSide.add(helpAnchor);
				
				//locale anchors
				rightSide.add(newLocaleAnchor("en", currentLocale));
				rightSide.add(newLocaleAnchor("ru", currentLocale));				
			}
		}			
		
		RootPanel.get("topPanel").add(topPanel);
		
		/////////////////////////////////////////////////////////////
		
		HorizontalPanel newFeedPanel = new HorizontalPanel();
		newFeedPanel.setStyleName("newFeedPanel");
		
		newFeedPanel.add(new Label(i18nc.newFeed() + ":"));
		
		newFeedTextbox = new TextBox();
		newFeedTextbox.setStyleName("newFeedTextbox");
		newFeedTextbox.setTitle(i18nc.newFeedTooltip());
		newFeedPanel.add(newFeedTextbox);
		
		newFeedButton = new Button(i18nc.add());
		newFeedButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				displayTagcloudLoader();
				newFeedButton.setEnabled(false);
				newFeedTextbox.setEnabled(false);
				controllerState.newFeed(
						newFeedTextbox.getText(), 
						importantCheckbox.getValue() != null && importantCheckbox.getValue().booleanValue(), 
						MainPage.this
				);
			}
		});
		newFeedPanel.add(newFeedButton);
		
		importantCheckbox = new CheckBox(i18nc.important());
		importantCheckbox.setValue(false);
		importantCheckbox.setTitle(i18nc.importantCheckboxTooltip());
		newFeedPanel.add(importantCheckbox);
		
		RootPanel.get("newFeedPanel").add(newFeedPanel);
		
		/////////////////////////////////////////////////////////////
		
		HorizontalPanel tagcloudSubpanel = new HorizontalPanel();
		tagcloudSubpanel.setSpacing(5);
		
		settingsPanel = new SettingsPanel(i18nc, new SettingsPanelListener() {
			@Override
			public void onNEntriesValueChanged(long newValue) {
				Settings settings = user.getSettings();
				settings.setNEntriesToShow((int)newValue);
				displayTagcloudLoader();
				controllerState.modifySettings(settings, MainPage.this);
			}
		});
		settingsPanel.setHeight(TAGCLOUD_SUBPANEL_HEIGHT);
		
		feedsPanel = new FeedsPanel(i18nc, null);
		feedsPanel.setListener(new FeedsPanelListener() {
			
			@Override
			public void onFeedsSelectionChanged(ChangeEvent event) {
				assert(user != null);
				Feed feed = user.getFeeds().get(feedsPanel.getFeedsListbox().getSelectedIndex());
				feedsPanel.getImportantCheckbox().setValue(feed.isImportant());
			}

			@Override
			public void onDeleteButtonClick(ClickEvent event) {
				int selectedIndex = feedsPanel.getFeedsListbox().getSelectedIndex();
				if(selectedIndex >= 0) {
					displayTagcloudLoader();
					controllerState.deleteFeed(
							user.getFeeds().get(selectedIndex).getUrl(),
							MainPage.this
					);
				}
			}

			@Override
			public void onImportantCheckboxValueChange(ValueChangeEvent<Boolean> event) {
				if(user == null || feedsPanel.getFeedsListbox().getSelectedIndex() < 0) return;
				
				Feed feed = user.getFeeds().get(feedsPanel.getFeedsListbox().getSelectedIndex());
				feed.setImportant(event.getValue().booleanValue());
				displayTagcloudLoader();
				controllerState.modifyFeed(feed, MainPage.this);
			}
		});
		feedsPanel.setHeight(TAGCLOUD_SUBPANEL_HEIGHT);
		
		tagcloudSubpanel.add(settingsPanel);
		tagcloudSubpanel.add(feedsPanel);
		
		RootPanel.get("tagcloudSubpanel").add(tagcloudSubpanel);
		
		//////////////////////////////////////////////////////////
		
		Button refreshButton = new Button(i18nc.refresh());
		refreshButton.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				displayTagcloudLoader();
				controllerState.updateFeeds(MainPage.this);
			}
		});
		RootPanel.get("refreshButtonPanel").add(refreshButton);
		
		//////////////////////////////////////////////////////////
		
		displayTagcloudLoader();
		newFeedTextbox.setEnabled(false);
		newFeedButton.setEnabled(false);
		
		//retrieve user information
		controllerState.getUser(this);
	}

	private String getLocalizedUrl(String localeName) {
		String base = Window.Location.getHref();
		
		try {
			String[] split = base.split("[\\?&]locale=", 2);
			if(split.length > 1) { //the locale is already there
				String[] split2 = split[1].split("[\\?&]", 2);
				return 
					split[0] + //first part before locale 
					base.substring(split[0].length(), split[0].length() + 1) + //? or & sign
					"locale=" + localeName + 
					(split2.length > 1 ? 
							split[1].substring(split2[0].length(), split2[0].length() + 1) + split2[1] : //? or & sign and the rest of base 
							"" //nothing after locale definition so we return ""
					); 
			}
		}
		catch(Exception e) {
			//TODO: log this somewhere
		}
		
		if(base.endsWith("/"))
			return base.substring(0, base.length() - 1) + "?locale=" + localeName;
		
		return base + "&locale=" + localeName;
	}

	@Override
	public void newFeedError(String msg) {
		Window.alert("Failed to add new feed. " + msg);
		refreshTagcloudWidget();
		newFeedButton.setEnabled(true);
		newFeedTextbox.setEnabled(true);
	}

	@Override
	public void newFeedOk(User user, Feed feed) {
		newFeedTextbox.setText("");
		importantCheckbox.setValue(false);
		refreshTagcloudWidget();
		newFeedButton.setEnabled(true);
		newFeedTextbox.setEnabled(true);
		
		if(feed.isValid()) {
			feedsPanel.getFeedsListbox().addItem(feed.getTitle());
		}
		else {
			feedsPanel.getFeedsListbox().addItem("[" + feed.getUrl() + "]");
			Window.alert(i18nc.yourFeedIsInvalid());
		}
	}

	@Override
	public void getUserOk(User user) {
		this.user = user;
		userLoginLabel.setText(user.getLogin());
		newFeedButton.setEnabled(true);
		newFeedTextbox.setEnabled(true);
		settingsPanel.setNEntries(user.getSettings().getNEntriesToShow());
		
		JsArray<Feed> feeds = user.getFeeds();
		if(feeds.length() > 0) {
			boolean hasInvalidFeeds = false;
			for(int i = 0; i < feeds.length(); i++) {
				Feed feed = feeds.get(i); 
				if(feed.isValid()) {
					feedsPanel.getFeedsListbox().addItem(feed.getTitle());
				}
				else {
					hasInvalidFeeds = true;
					feedsPanel.getFeedsListbox().addItem("[" + feed.getUrl() + "]");
				}
			}
			refreshTagcloudWidget();
			
			if(hasInvalidFeeds) {
				Window.alert(i18nc.youHaveInvalidFeeds());
			}
		}
		else {
			displayTagcloudWidgetLabel(i18nc.noFeeds());
		}
	}
	
	@Override
	public void getUserError(String msg) {
		Window.alert("Failed to retrieve user information: " + msg);
		displayTagcloudWidgetLabel(i18nc.noConnectionToServer());
	}

	private native void refreshTagcloudWidget() /*-{
		$wnd.refreshTagcloud();
	}-*/;
	
	private native void displayTagcloudLoader() /*-{
		$wnd.displayTagcloudLoader();
	}-*/;
	
	private native void displayTagcloudWidgetLabel(String text) /*-{
		$wnd.displayTagcloudWidgetLabel(text);
	}-*/; 

	@Override
	public void deleteFeedError(String msg) {
		Window.alert("Failed to remove feed. " + msg);
		refreshTagcloudWidget();
	}

	@Override
	public void deleteFeedOk(User user, String feedUrl) {
		removeFeedFromListbox(feedUrl);
		
		genericOkAction(user);
	}

	private void removeFeedFromListbox(String feedUrl) {
		JsArray<Feed> feeds = user.getFeeds();
		for(int i = 0; i < feeds.length(); i++) {
			if(feeds.get(i).getUrl().equals(feedUrl)) {
				feedsPanel.getFeedsListbox().removeItem(i);
				user.removeFeed(i);
				break;
			}
		}
	}

	@Override
	public void modifyFeedError(String msg) {
		Window.alert("Failed to modify feed. " + msg);
		feedsPanel.getImportantCheckbox().setValue(!feedsPanel.getImportantCheckbox().getValue(), false);
		refreshTagcloudWidget();
	}

	@Override
	public void modifyFeedOk(User user, Feed feed) {
		genericOkAction(user);
	}

	@Override
	public void updateFeedsError(String msg) {
		Window.alert("Failed to update feeds. " + msg);
		refreshTagcloudWidget();
	}

	@Override
	public void updateFeedsOk(User user) {
		refreshTagcloudWidget();		
	}

	@Override
	public void modifySettingsError(String msg) {
		Window.alert("Failed to modify settings. " + msg);
		refreshTagcloudWidget();
	}

	@Override
	public void modifySettingsOk(User user, Settings settings) {
		genericOkAction(user);
	}

	private void genericOkAction(User user) {
		if(user.getFeeds().length() > 0)
			refreshTagcloudWidget();
		else
			displayTagcloudWidgetLabel(i18nc.noFeeds());
	}

	@Override
	public void onInternalServerError(String response) {
		Window.alert("Internal server error!\nData:\n" + response);
		
		String currentLocale = LocaleInfo.getCurrentLocale().getLocaleName();
		if(currentLocale.equals("default")) currentLocale = "en";
		Window.open(GWT.getHostPageBaseURL() + currentLocale + "/ko-internal.html", "ko-internal.html", "");
		
	}
}
